package com.pinfly.common.config;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;

import org.apache.log4j.Logger;

import com.pinfly.common.util.StringUtil;

/**
 * This class provides the implementation to read an XML based configuration
 * file that is in the Pinfly format. Refer to some existing core xml-based
 * properties as an example database.xml, etc.
 * 
 * This implementation is used by default or can be set using the following
 * system property.
 * 
 * pinfly.cfgprop.impl=net.pinfly.config.filesystem.impl.PfyPropertiesXMLImpl
 * 
 */
public class PfyPropertiesXMLImpl implements IPfyProperties
{
    private static final Logger logger = Logger.getLogger (PfyPropertiesXMLImpl.class);

    // Private methods

    /**
     * Returns a valid path for the specified group
     * 
     * @param group
     * @return filePath
     * @throws ConfigException
     */
    private String getValidPropertiesFilepath (String group) throws ConfigException
    {
        StringBuffer filePath = new StringBuffer ();
        filePath.append (BaseConfigUtil.getPfyPropertiesDir ());
        filePath.append (System.getProperty ("file.separator"));
        filePath.append (group);
        filePath.append (BaseConfigConstants.XMLFILE_EXT);

        File f = new File (filePath.toString ());
        if (f.exists ())
        {
            return filePath.toString ();
        }
        else
        {
            throw new ConfigException ("xml properties file doesn't exist at " + filePath.toString ());
        }
    }

    /**
     * Returns the PfyProperties for the group using the specified filepath.
     * 
     * @param filepath
     * @param group
     * @return PfyProperties
     * @throws ConfigException
     */
    private PfyProperties getPropertiesUsingFile (String filepath, String group) throws ConfigException
    {

        if (logger.isTraceEnabled ())
        {
            logger.trace (new Object[]
            { "filepath=" + filepath, "group=" + group });
        }

        if (StringUtil.isNullOrBlank (filepath))
        {
            throw new IllegalArgumentException ("filepath can't be null or empty string");
        }
        if (StringUtil.isNullOrBlank (group))
        {
            throw new IllegalArgumentException ("group can't be null or empty string");
        }

        PfyProperties prop = PfyXMLUtil.getInstance ().readXMLPropertiesFile (filepath, group);

        if (logger.isTraceEnabled ())
        {
            logger.trace ("PfyProperties for group=" + group + " has (" + prop.size () + ") parameters.");
        }
        return prop;
    }

    // Public Methods

    public PfyProperties getProperties (String group) throws ConfigException
    {
        if (logger.isTraceEnabled ())
        {
            logger.trace (new Object[]
            { "group=" + group });
        }

        if (StringUtil.isNullOrBlank (group))
        {
            throw new IllegalArgumentException ("group can't be null or empty string");
        }

        String filepath = getValidPropertiesFilepath (group);
        PfyProperties prop = getPropertiesUsingFile (filepath, group);
        if (logger.isTraceEnabled ())
        {
            logger.trace ("PfyProperties for group=" + group + " has (" + prop.size () + ") parameters.");
        }
        return prop;
    }

    public Collection <PfyProperties> getProperties (Collection <String> groupNames) throws ConfigException
    {
        if (logger.isTraceEnabled ())
        {
            logger.trace (new Object[]
            { "groupNames=" + groupNames });
        }

        if (groupNames == null || groupNames.size () == 0)
        {
            throw new IllegalArgumentException ("groupNames can't be null or empty");
        }

        Collection <PfyProperties> props = new ArrayList <PfyProperties> ();

        for (String group : groupNames)
        {
            String filepath = getValidPropertiesFilepath (group);
            PfyProperties prop = getPropertiesUsingFile (filepath, group);

            props.add (prop);
        }

        if (logger.isTraceEnabled ())
        {
            logger.trace ("Returning (" + props.size () + ") PfyProperties");
        }
        return props;
    }

    public GroupMap getPropertiesMap (Collection <String> groupNames) throws ConfigException
    {
        if (logger.isTraceEnabled ())
        {
            logger.trace (new Object[]
            { "groups=" + groupNames });
        }

        if (groupNames == null || groupNames.size () == 0)
        {
            throw new IllegalArgumentException ("groupNames can't be null or empty");
        }

        Collection <String> newGroupNames = FileSystemUtil.updateGroupNameWithWildCard (groupNames,
                                                                                        BaseConfigConstants.XMLFILE_EXT);

        GroupMap map = new GroupMap ();
        for (String group : newGroupNames)
        {
            String filepath = getValidPropertiesFilepath (group);
            PfyProperties prop = getPropertiesUsingFile (filepath, group);

            map.setProperties (group, prop);
        }

        if (logger.isTraceEnabled ())
        {
            logger.trace ("Returning (" + map.size () + ") PfyProperties in Map");
        }
        return map;
    }

    @Override
    public PfyProperties getProperties (String filePath, String groupName) throws ConfigException
    {
        if (StringUtil.isNullOrBlank (filePath))
        {
            throw new IllegalArgumentException ("filePath can't be null or empty string");
        }

        if (StringUtil.isNullOrBlank (groupName))
        {
            throw new IllegalArgumentException ("groupName can't be null or empty string");
        }

        PfyProperties prop = getPropertiesUsingFile (filePath, groupName);
        return prop;
    }

    @Override
    public Collection <PfyProperties> getProperties (String filePath, Collection <String> groupNames)
                                                                                                     throws ConfigException
    {
        if (StringUtil.isNullOrBlank (filePath))
        {
            throw new IllegalArgumentException ("filePath can't be null or empty string");
        }

        if (groupNames == null || groupNames.size () == 0)
        {
            throw new IllegalArgumentException ("groupNames can't be null or empty");
        }

        Collection <PfyProperties> props = new ArrayList <PfyProperties> ();

        for (String group : groupNames)
        {
            PfyProperties prop = getPropertiesUsingFile (filePath, group);

            props.add (prop);
        }

        return props;
    }

    @Override
    public GroupMap getPropertiesMap (String filePath, Collection <String> groupNames) throws ConfigException
    {
        if (StringUtil.isNullOrBlank (filePath))
        {
            throw new IllegalArgumentException ("filePath can't be null or empty string");
        }

        if (groupNames == null || groupNames.size () == 0)
        {
            throw new IllegalArgumentException ("groupNames can't be null or empty");
        }

        Collection <String> newGroupNames = FileSystemUtil.updateGroupNameWithWildCard (filePath, groupNames,
                                                                                        BaseConfigConstants.XMLFILE_EXT);

        GroupMap map = new GroupMap ();
        for (String group : newGroupNames)
        {
            PfyProperties prop = getPropertiesUsingFile (filePath, group);

            map.setProperties (group, prop);
        }

        return map;
    }

}
